package wang.lcs.pay.ali;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;

import wang.lcs.pay.config.AlipayConfig;
import wang.lcs.pay.util.WebUtil;
import wang.lcs.pay.util.print.LogHttpResult;

public abstract class AliCallback {

    private static final Logger log = LoggerFactory.getLogger(AliCallback.class);

    @Resource
    AlipayConfig config;

    /**
     * <pre>
     * Parameters = {gmt_create=[2018-06-21 10:05:50], charset=[utf8], seller_email=[fbqajs2583@sandbox.com], subject=[测试], sign=[......], body=[测试描述文字], buyer_id=[2088102176194205], invoice_amount=[0.01], notify_id=[408065de951a4a832a08c05eda72974hjm], fund_bill_list=[[{"amount":"0.01","fundChannel":"ALIPAYACCOUNT"}]], notify_type=[trade_status_sync], trade_status=[TRADE_SUCCESS], receipt_amount=[0.01], app_id=[2016091400511654], buyer_pay_amount=[0.01], sign_type=[RSA2], seller_id=[2088102175637198], gmt_payment=[2018-06-21 10:05:51], notify_time=[2018-06-21 10:05:52], version=[1.0], out_trade_no=[2018621103811425], total_amount=[0.01], trade_no=[2018062121001004200200632175], auth_app_id=[2016091400511654], buyer_logon_id=[ebl***@sandbox.com], point_amount=[0.00]}
     * Parameters = {gmt_create=[2018-06-21 10:08:07], charset=[utf8], gmt_payment=[2018-06-21 10:08:20], notify_time=[2018-06-21 10:08:21], subject=[测试], sign=[......], buyer_id=[2088102176194205], body=[测试描述], invoice_amount=[0.01], version=[1.0], notify_id=[d2e140fbbef030b855d855037eafb32hjm], fund_bill_list=[[{"amount":"0.01","fundChannel":"ALIPAYACCOUNT"}]], notify_type=[trade_status_sync], out_trade_no=[20186211072820397], total_amount=[0.01], trade_status=[TRADE_SUCCESS], trade_no=[2018062121001004200200632176], auth_app_id=[2016091400511654], receipt_amount=[0.01], point_amount=[0.00], app_id=[2016091400511654], buyer_pay_amount=[0.01], sign_type=[RSA2], seller_id=[2088102175637198]}
     * </pre>
     * 
     */
    @RequestMapping("/notify")
    @ResponseBody
    public String httpNotify(HttpServletRequest request, HttpServletResponse response, //
            @RequestParam(name = "out_trade_no") String outTradeNo, //
            @RequestParam(name = "trade_no") String tradeNo, @RequestParam(name = "trade_status") String status)//
            throws AlipayApiException, JsonParseException, JsonMappingException, JsonProcessingException, IOException {

        log.info("Ali notify [{}] ! {} : {}", outTradeNo, tradeNo);
        if (log.isDebugEnabled()) {
            new LogHttpResult(log).print(request, response);
        }
        boolean signVerfied = checkSign(request);

        Map<String, String> model = WebUtil.request2map(request);
        if (signVerfied) {
            if ("TRADE_FINISHED".equals(status)) {
                return doTradeFinished(model, request, response);
            } else if ("TRADE_SUCCESS".equals(status)) {
                return doTradeSuccess(model, request, response);
            }
        }
        return doNotifyError(request, response);
    }

    protected String doNotifyError(HttpServletRequest request, HttpServletResponse response) throws IOException {
        new LogHttpResult(log).print(request, response);
        return "fail";
    }

    protected String doTradeFinished(Map<String, String> model, HttpServletRequest request, HttpServletResponse response) throws IOException {
        return "success";
    }

    protected String doTradeSuccess(Map<String, String> model, HttpServletRequest request, HttpServletResponse response) throws IOException {
        return "success";
    }

    /**
     * <pre>
     * Parameters = {charset=[utf8], out_trade_no=[2018621103811425] , method=[alipay.trade.wap.pay.return], total_amount=[0.01], sign=[......], trade_no=[2018062121001004200200632175], auth_app_id=[2016091400511654], version=[1.0], app_id=[2016091400511654], sign_type=[RSA2], seller_id=[2088102175637198], timestamp=[2018-06-21 10:05:54]}
     * Parameters = {charset=[utf8], out_trade_no=[20186211072820397], method=[alipay.trade.page.pay.return], total_amount=[0.01], sign=[......], trade_no=[2018062121001004200200632176], auth_app_id=[2016091400511654], version=[1.0], app_id=[2016091400511654], sign_type=[RSA2], seller_id=[2088102175637198], timestamp=[2018-06-21 10:08:28]}
     * </pre>
     * 
     */
    @RequestMapping("/return")
    public Object httpReturn(HttpServletRequest request, HttpServletResponse response, @RequestParam(required = false, defaultValue = "-") String method, //
            @RequestParam(name = "out_trade_no") String outTradeNo, @RequestParam(name = "trade_no") String tradeNo)//
            throws AlipayApiException, JsonParseException, JsonMappingException, JsonProcessingException, IOException {

        log.info("Ali pay return [{}] ! {} : {}", method, outTradeNo, tradeNo);
        if (log.isDebugEnabled()) {
            new LogHttpResult(log).print(request, response);
        }
        // 获取支付宝POST过来反馈信息
        boolean signVerfied = checkSign(request);
        if (signVerfied) {// 验证成功
            Map<String, String> model = WebUtil.request2map(request);
            return doReturn(model, request, response);
        } else {// 验证失败
            new LogHttpResult(log).print(request, response);
            return doReturnSignError(request, response);
        }
    }

    private Object doReturnSignError(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.getWriter().write("<html><body><h1>Error : 签名出错</h1></body></html>");
        return null;
    }

    protected Object doReturn(Map<String, String> model, HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.getWriter().write("<html><body><h1>Ok</h1></body></html>");
        return null;
    }

    protected void doReturnError(Map<String, String> model, HttpServletRequest request, HttpServletResponse response) throws IOException {
        // TODO : success
        response.getWriter().write("<html><body><h1>Error : 签名出错</h1></body></html>");
    }

    public boolean checkSign(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        return AlipaySignature.rsaCheckV1(params, config.getAlipayPublicKey(), AlipayConfig.UTF_8_CHARSET, config.getSignType());
    }
}
